package com.example.examsystem.service;

import com.example.examsystem.dto.ExamAnswerDto;
import com.example.examsystem.dto.ExamRecordDto;
import com.example.examsystem.dto.PageResponse;
import com.example.examsystem.exception.BusinessException;
import com.example.examsystem.model.*;
import com.example.examsystem.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import com.example.examsystem.dto.ExamStatisticsDto;

/**
 * 考试记录服务
 * 处理考试记录相关的业务逻辑
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ExamRecordService {
    
    private final ExamRecordRepository examRecordRepository;
    private final ExamRepository examRepository;
    private final UserRepository userRepository;
    private final ExamAnswerRepository examAnswerRepository;
    private final QuestionRepository questionRepository;
    private final ExamQuestionRepository examQuestionRepository;
    
    /**
     * 分页查询考试记录列表
     * @param page 页码
     * @param size 每页大小
     * @param examId 考试ID
     * @param userId 用户ID
     * @param username 用户名
     * @param examTitle 考试标题
     * @param status 状态
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 分页考试记录数据
     */
    public PageResponse<ExamRecordDto> getExamRecords(int page, int size, Long examId, Long userId,
                                                     String username, String examTitle, String status, String startTime, String endTime) {
        log.debug("查询考试记录列表 - 页码: {}, 大小: {}, 筛选条件: 考试ID={}, 用户ID={}, 用户名={}, 考试标题={}, 状态={}, 开始时间={}, 结束时间={}", 
                page, size, examId, userId, username, examTitle, status, startTime, endTime);
        
        LocalDateTime startDateTime = null;
        LocalDateTime endDateTime = null;
        
        if (startTime != null && !startTime.isEmpty()) {
            startDateTime = LocalDateTime.parse(startTime, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        }
        if (endTime != null && !endTime.isEmpty()) {
            endDateTime = LocalDateTime.parse(endTime, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        }
        
        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
        Page<ExamRecord> recordPage = examRecordRepository.findByQuery(
            examId, userId, username, examTitle, status, startDateTime, endDateTime, pageable);
        
        List<ExamRecordDto> content = recordPage.getContent().stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
        
        return new PageResponse<>(
            content,
            recordPage.getNumber(),
            recordPage.getSize(),
            recordPage.getTotalElements(),
            recordPage.getTotalPages()
        );
    }
    
    /**
     * 获取考试记录详情
     * @param id 记录ID
     * @return 考试记录详情
     */
    public ExamRecordDto getExamRecord(Long id) {
        log.debug("获取考试记录详情 - ID: {}", id);
        ExamRecord record = examRecordRepository.findById(id)
            .orElseThrow(() -> new BusinessException("考试记录不存在"));
        return convertToDto(record);
    }
    
    /**
     * 开始考试
     * @param examId 考试ID
     * @param userId 用户ID
     * @param ipAddress IP地址
     * @param userAgent 用户代理
     * @return 考试记录
     */
    @Transactional
    public ExamRecordDto startExam(Long examId, Long userId, String ipAddress, String userAgent) {
        log.debug("开始考试 - 考试ID: {}, 用户ID: {}", examId, userId);
        
        // 检查考试是否存在
        Exam exam = examRepository.findById(examId)
            .orElseThrow(() -> new BusinessException("考试不存在"));
        
        // 检查用户是否存在
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new BusinessException("用户不存在"));
        
        // 检查考试状态和时间
        LocalDateTime now = LocalDateTime.now();
        if (exam.getStartTime().isAfter(now)) {
            throw new BusinessException("考试尚未开始");
        }
        if (exam.getEndTime().isBefore(now)) {
            throw new BusinessException("考试已结束");
        }
        
        // 检查用户是否已经参加过考试
        long recordCount = examRecordRepository.countByUserIdAndExamId(userId, examId);
        if (recordCount >= exam.getMaxAttempts()) {
            throw new BusinessException("已达到最大考试次数限制");
        }
        
        // 检查是否有进行中的考试
        List<ExamRecord> inProgressRecords = examRecordRepository.findByUserIdAndExamId(userId, examId)
            .stream()
            .filter(record -> "IN_PROGRESS".equals(record.getStatus()))
            .collect(Collectors.toList());
        
        if (!inProgressRecords.isEmpty()) {
            throw new BusinessException("您有正在进行的考试，请先完成或放弃当前考试");
        }
        
        // 创建考试记录
        ExamRecord record = new ExamRecord();
        record.setExamId(examId);
        record.setUserId(userId);
        record.setStartTime(now);
        record.setDuration(exam.getDuration());
        record.setTotalScore(exam.getTotalScore());
        record.setStatus("IN_PROGRESS");
        record.setIpAddress(ipAddress);
        record.setUserAgent(userAgent);
        record.setCreatedAt(now);
        record.setUpdatedAt(now);
        
        ExamRecord savedRecord = examRecordRepository.save(record);
        log.info("考试开始成功 - 记录ID: {}, 考试ID: {}, 用户ID: {}", savedRecord.getId(), examId, userId);
        
        return convertToDto(savedRecord);
    }
    
    /**
     * 提交答案
     * @param recordId 记录ID
     * @param answers 答案列表
     * @return 更新的考试记录
     */
    @Transactional
    public ExamRecordDto submitAnswers(Long recordId, List<ExamAnswerDto> answers) {
        log.debug("提交答案 - 记录ID: {}, 答案数量: {}", recordId, answers.size());
        
        ExamRecord record = examRecordRepository.findById(recordId)
            .orElseThrow(() -> new BusinessException("考试记录不存在"));
        
        if (!"IN_PROGRESS".equals(record.getStatus())) {
            throw new BusinessException("考试已结束，无法提交答案");
        }
        
        // 删除原有答案
        examAnswerRepository.deleteByExamRecordId(recordId);
        
        // 保存新答案
        for (ExamAnswerDto answerDto : answers) {
            ExamAnswer answer = new ExamAnswer();
            answer.setExamRecordId(recordId);
            answer.setQuestionId(answerDto.getQuestionId());
            answer.setAnswer(answerDto.getAnswer());
            answer.setCreatedAt(LocalDateTime.now());
            
            examAnswerRepository.save(answer);
        }
        
        record.setUpdatedAt(LocalDateTime.now());
        examRecordRepository.save(record);
        
        log.info("答案提交成功 - 记录ID: {}, 答案数量: {}", recordId, answers.size());
        
        return convertToDto(record);
    }
    
    /**
     * 完成考试
     * @param recordId 记录ID
     * @return 完成的考试记录
     */
    @Transactional
    public ExamRecordDto finishExam(Long recordId) {
        log.debug("完成考试 - 记录ID: {}", recordId);
        
        ExamRecord record = examRecordRepository.findById(recordId)
            .orElseThrow(() -> new BusinessException("考试记录不存在"));
        
        if (!"IN_PROGRESS".equals(record.getStatus())) {
            throw new BusinessException("考试已结束");
        }
        
        LocalDateTime now = LocalDateTime.now();
        record.setEndTime(now);
        record.setStatus("COMPLETED");
        record.setUpdatedAt(now);
        
        // 计算得分
        calculateScore(record);
        
        ExamRecord savedRecord = examRecordRepository.save(record);
        log.info("考试完成 - 记录ID: {}, 得分: {}", recordId, savedRecord.getScore());
        
        return convertToDto(savedRecord);
    }
    
    /**
     * 获取用户的考试记录
     * @param userId 用户ID
     * @param page 页码
     * @param size 每页大小
     * @param examId 考试ID
     * @param status 状态
     * @return 分页考试记录数据
     */
    public PageResponse<ExamRecordDto> getMyExamRecords(Long userId, int page, int size, Long examId, String status) {
        log.debug("获取用户考试记录 - 用户ID: {}, 页码: {}, 大小: {}, 考试ID: {}, 状态: {}", 
                userId, page, size, examId, status);
        
        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
        Page<ExamRecord> recordPage = examRecordRepository.findMyRecords(userId, examId, status, pageable);
        
        List<ExamRecordDto> content = recordPage.getContent().stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
        
        return new PageResponse<>(
            content,
            recordPage.getNumber(),
            recordPage.getSize(),
            recordPage.getTotalElements(),
            recordPage.getTotalPages()
        );
    }
    
    /**
     * 获取考试统计信息
     * @param examId 考试ID
     * @return 统计信息
     */
    public ExamStatisticsDto getExamStatistics(Long examId) {
        log.debug("获取考试统计信息 - 考试ID: {}", examId);

        Map<String, Object> statsMap = examRecordRepository.getExamStatistics(examId);
        
        ExamStatisticsDto dto = new ExamStatisticsDto();
        dto.setTotalCount(((Number) statsMap.get("totalCount")).longValue());
        dto.setCompletedCount(((Number) statsMap.get("completedCount")).longValue());
        dto.setInProgressCount(((Number) statsMap.get("inProgressCount")).longValue());
        dto.setAvgScore(statsMap.get("avgScore") != null ? (BigDecimal) statsMap.get("avgScore") : BigDecimal.ZERO);
        dto.setMaxScore(statsMap.get("maxScore") != null ? (BigDecimal) statsMap.get("maxScore") : BigDecimal.ZERO);
        dto.setMinScore(statsMap.get("minScore") != null ? (BigDecimal) statsMap.get("minScore") : BigDecimal.ZERO);

        // 添加及格人数统计(60分及以上为及格)
        long passCount = examRecordRepository.countByExamIdAndScoreGreaterThanEqual(examId, BigDecimal.valueOf(60));
        dto.setPassCount(passCount);
        
        // 获取成绩分布数据
        dto.setScoreDistribution(getScoreDistribution(examId));
        
        return dto;
    }
    
    /**
     * 获取成绩分布数据
     * @param examId 考试ID
     * @return 成绩分布数据
     */
    private List<ExamStatisticsDto.ScoreDistributionDto> getScoreDistribution(Long examId) {
        // 查询所有完成考试的记录分数
        List<BigDecimal> scores = examRecordRepository.findScoresByExamIdAndStatus(examId, "COMPLETED");
        
        // 初始化各分数段计数数组(0-100分，每10分为一个区间)
        int[] scoreCounts = new int[11];
        
        // 统计各分数段人数
        for (BigDecimal score : scores) {
            if (score != null) {
                int scoreValue = score.intValue();
                // 确保分数在有效范围内
                if (scoreValue >= 0 && scoreValue <= 100) {
                    // 计算分数段索引
                    int index = Math.min(scoreValue / 10, 10);
                    scoreCounts[index]++;
                }
            }
        }
        
        // 转换为DTO列表
        return IntStream.range(0, scoreCounts.length)
                .mapToObj(i -> {
                    ExamStatisticsDto.ScoreDistributionDto distributionDto = new ExamStatisticsDto.ScoreDistributionDto();
                    if (i < 10) {
                        distributionDto.setScoreRange(i * 10 + "-" + (i * 10 + 9));
                    } else {
                        // 最后一个区间是100分
                        distributionDto.setScoreRange("100");
                    }
                    distributionDto.setCount(scoreCounts[i]);
                    return distributionDto;
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 计算考试得分
     * @param record 考试记录
     */
    private void calculateScore(ExamRecord record) {
        List<ExamAnswer> answers = examAnswerRepository.findByExamRecordId(record.getId());
        BigDecimal totalScore = BigDecimal.ZERO;
        
        for (ExamAnswer answer : answers) {
            // TODO: 根据题目类型和正确答案计算得分
            // 这里需要实现具体的评分逻辑
        }
        
        record.setScore(totalScore);
    }
    
    /**
     * 转换为DTO
     * @param record 考试记录实体
     * @return 考试记录DTO
     */
    private ExamRecordDto convertToDto(ExamRecord record) {
        ExamRecordDto dto = new ExamRecordDto();
        dto.setId(record.getId());
        dto.setExamId(record.getExamId());
        dto.setUserId(record.getUserId());
        dto.setStartTime(record.getStartTime());
        dto.setEndTime(record.getEndTime());
        dto.setDuration(record.getDuration());
        dto.setScore(record.getScore());
        dto.setTotalScore(record.getTotalScore());
        dto.setStatus(record.getStatus());
        dto.setIpAddress(record.getIpAddress());
        dto.setUserAgent(record.getUserAgent());
        dto.setRemarks(record.getRemarks());
        dto.setCreatedAt(record.getCreatedAt());
        dto.setUpdatedAt(record.getUpdatedAt());
        
        // 设置考试标题
        if (record.getExam() != null) {
            dto.setExamTitle(record.getExam().getTitle());
        }
        
        // 设置用户信息
        if (record.getUser() != null) {
            dto.setUsername(record.getUser().getUsername());
            dto.setFullName(record.getUser().getFullName());
        }
        
        // 设置答案列表
        if (record.getAnswers() != null) {
            List<ExamAnswerDto> answerDtos = record.getAnswers().stream()
                .map(this::convertAnswerToDto)
                .collect(Collectors.toList());
            dto.setAnswers(answerDtos);
        }
        
        return dto;
    }
    
    /**
     * 转换答案为DTO
     * @param answer 答案实体
     * @return 答案DTO
     */
    private ExamAnswerDto convertAnswerToDto(ExamAnswer answer) {
        ExamAnswerDto dto = new ExamAnswerDto();
        dto.setId(answer.getId());
        dto.setExamRecordId(answer.getExamRecordId());
        dto.setQuestionId(answer.getQuestionId());
        dto.setAnswer(answer.getAnswer());
        dto.setCreatedAt(answer.getCreatedAt());
        
        // 设置题目信息
        if (answer.getQuestion() != null) {
            dto.setQuestionTitle(answer.getQuestion().getTitle());
            dto.setQuestionType(answer.getQuestion().getType().getDescription());
        }
        
        return dto;
    }
    
    /**
     * 放弃考试
     * @param recordId 记录ID
     * @return 放弃的考试记录
     */
    @Transactional
    public ExamRecordDto abandonExam(Long recordId) {
        log.debug("放弃考试 - 记录ID: {}", recordId);
        
        ExamRecord record = examRecordRepository.findById(recordId)
            .orElseThrow(() -> new BusinessException("考试记录不存在"));
        
        if (!"IN_PROGRESS".equals(record.getStatus())) {
            throw new BusinessException("考试已结束");
        }
        
        LocalDateTime now = LocalDateTime.now();
        record.setEndTime(now);
        record.setStatus("ABANDONED");
        record.setUpdatedAt(now);
        
        ExamRecord savedRecord = examRecordRepository.save(record);
        log.info("考试放弃 - 记录ID: {}", recordId);
        
        return convertToDto(savedRecord);
    }
    
    /**
     * 删除考试记录
     * @param id 记录ID
     */
    @Transactional
    public void deleteExamRecord(Long id) {
        log.debug("删除考试记录 - ID: {}", id);
        
        ExamRecord record = examRecordRepository.findById(id)
            .orElseThrow(() -> new BusinessException("考试记录不存在"));
        
        // 删除相关答案
        examAnswerRepository.deleteByExamRecordId(id);
        
        // 删除记录
        examRecordRepository.delete(record);
        log.info("考试记录删除成功 - ID: {}", id);
    }
    
    /**
     * 批量删除考试记录
     * @param ids 记录ID列表
     * @return 删除数量
     */
    @Transactional
    public int batchDeleteExamRecords(List<Long> ids) {
        log.debug("批量删除考试记录 - 数量: {}", ids.size());
        
        int deletedCount = 0;
        for (Long id : ids) {
            try {
                deleteExamRecord(id);
                deletedCount++;
            } catch (Exception e) {
                log.warn("删除考试记录失败 - ID: {}, 错误: {}", id, e.getMessage());
            }
        }
        
        log.info("批量删除考试记录完成 - 删除数量: {}", deletedCount);
        return deletedCount;
    }
    
    /**
     * 获取考试进度
     * @param recordId 记录ID
     * @return 考试进度信息
     */
    public Map<String, Object> getExamProgress(Long recordId) {
        log.debug("获取考试进度 - 记录ID: {}", recordId);
        
        ExamRecord record = examRecordRepository.findById(recordId)
            .orElseThrow(() -> new BusinessException("考试记录不存在"));
        
        if (!"IN_PROGRESS".equals(record.getStatus())) {
            throw new BusinessException("考试未进行中");
        }
        
        // 获取已答题数量
        long answeredCount = examAnswerRepository.countByExamRecordId(recordId);
        
        // 获取总题数
        Exam exam = examRepository.findById(record.getExamId())
            .orElseThrow(() -> new BusinessException("考试不存在"));
        long totalQuestions = examQuestionRepository.countByExamId(exam.getId());
        
        // 计算剩余时间
        LocalDateTime now = LocalDateTime.now();
        long elapsedMinutes = java.time.Duration.between(record.getStartTime(), now).toMinutes();
        long remainingMinutes = Math.max(0, record.getDuration() - elapsedMinutes);
        
        Map<String, Object> progress = new HashMap<>();
        progress.put("recordId", recordId);
        progress.put("answeredCount", answeredCount);
        progress.put("totalQuestions", totalQuestions);
        progress.put("elapsedMinutes", elapsedMinutes);
        progress.put("remainingMinutes", remainingMinutes);
        progress.put("progressPercentage", totalQuestions > 0 ? (answeredCount * 100.0 / totalQuestions) : 0);
        
        return progress;
    }
}